package com.lsec.springbootinit.service.impl;

import com.lsec.springbootinit.constant.CacheConstants;
import com.lsec.springbootinit.model.common.LoginUser;
import com.lsec.springbootinit.model.entity.SysUser;
import com.lsec.springbootinit.model.vo.auth.AuthLoginReqVO;
import com.lsec.springbootinit.model.vo.auth.AuthLoginRespVO;
import com.lsec.springbootinit.security.utils.SecurityFrameworkUtils;
import com.lsec.springbootinit.service.SysLoginService;
import com.lsec.springbootinit.service.TokenService;
import com.lsec.springbootinit.utils.RedisCache;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Optional;

import static com.lsec.springbootinit.exception.enums.TypicalCode.UNAUTHORIZED_401;
import static com.lsec.springbootinit.model.common.ServiceException.exception;

/**
 * 系统登录服务
 *
 * @author Cherry
 * @date 2023-06-25 16:45
 */


@Service
@RequiredArgsConstructor
public class SysLoginServiceImpl implements SysLoginService {

    private final AuthenticationManager authenticationManager;
    private final RedisCache redisCache;
    private final TokenService tokenService;


    /**
     * 登录
     *
     * @param authLoginReqVO 用户名/密码
     * @return {@link AuthLoginRespVO}
     */
    @Override
    public AuthLoginRespVO login(AuthLoginReqVO authLoginReqVO) {

        // TODO: 2023/6/26 验证码

        // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(authLoginReqVO.getUsername(),authLoginReqVO.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        Long userId = loginUser.getSysUser().getId();

        // 生成token
        String token = tokenService.createToken(userId);

        //authenticate存入redis 并且存入过期时间
        tokenService.refreshToken(loginUser);
        //把token响应给前端
        return AuthLoginRespVO.builder()
                .accessToken(token)
                .build();
        // TODO: 2023/6/26 登录日志
    }

    @Override
    public Boolean logout() {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();

        Long userId = Optional.ofNullable(loginUser)
                .map(LoginUser::getSysUser)
                .map(SysUser::getId)
                .orElseThrow(() -> exception(UNAUTHORIZED_401));

        return redisCache.deleteObject(CacheConstants.AUTH_USER_KEY + userId);
    }
}
